package timing.ukulele.flow.controller;

import timing.ukulele.flow.service.FlowUserInfoService;
import timing.ukulele.common.ResponseResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.*;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 启动流程实例
 */

@RestController
@Api(tags = "启动流程实例")
@Slf4j
public class StartController {

    @Autowired
    private FlowUserInfoService flowUserInfoService;

    private final RuntimeService runtimeService;
    private final ProcessEngine processEngine;
    private final TaskService taskService;
    private final RepositoryService repositoryService;


    public StartController(RuntimeService runtimeService, ProcessEngine processEngine, TaskService taskService,
        RepositoryService repositoryService) {
        this.runtimeService = runtimeService;
        this.processEngine = processEngine;
        this.taskService = taskService;
        this.repositoryService = repositoryService;
    }

    @PostMapping(path = "start")
    @ApiOperation(value = "根据流程key启动流程,procInstId为启动部署流程后生成的实例流程id,"
        + "processDefinitionKey为流程processKey和定义id的合成值, taskId为待办任务id, "
        + "assignee为待办任务的执行人",
                  notes = "每一个流程有对应的一个key这个是某一个流程内固定的写在bpmn内的")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "processKey", value = "流程key", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "userKey", value = "启动流程的用户", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "assignee", value = "下个任务执行人", dataType = "String", paramType = "query")
    })
    public ResponseResult start(@RequestParam("userKey") String startUserId,
                                @RequestParam("processKey") String processKey,
                                @RequestParam("assignee") String assignee
        // @ApiParam("部门编码") @RequestParam(value = "depcode", required = false) String depcode,
        // @ApiParam("区域编码") @RequestParam(value = "areacode", required = false) String areacode,
        // @ApiParam("角色名称（逗号隔开）") @RequestParam(value = "roles", required = false) String roles,
        // @ApiParam("角色是否是与的关系（1:是，0：否）") @RequestParam(value = "isand", required = false) String isand,
        // @ApiParam("用户类型（1:政府,2:企业）") @RequestParam(value = "usertype", required = false) String usertype,
        // @ApiParam("流程启动用户loginame") @RequestParam(value = "startuser", required = false) String startuser,
        // @ApiParam("流程当前用户loginame") @RequestParam(value = "flowuser", required = false) String flowuser,
        // @ApiParam("规则") @RequestParam(value = "rulecode", required = false) String rulecode
        ) {
        HashMap<String, Object> variables = new HashMap<>(2);
        variables.put("startUserId", startUserId);
        variables.put("assignee", "jh");

        ProcessInstance instance;
        try {
            instance = runtimeService
                    .startProcessInstanceByKey(processKey, variables);
            // Task task = processEngine.getTaskService().createTaskQuery().processInstanceId(instance.getId()).active().singleResult();
            // task.setAssignee("jh");
            // processEngine.getTaskService().saveTask(task);
        } catch (Exception e) {
            log.error(e.getMessage());
            return ResponseResult.error("启动失败:" + e.getMessage());
        }

        if (instance != null) {
            Map<String, String> result = new HashMap<>(4);
            // 流程实例ID
            result.put("procInstId", instance.getId());
            // 流程定义ID
            result.put("processDefinitionKey", instance.getProcessDefinitionId());

            //获取接口执行人
            // List<User> userList =
            //     flowUserInfoService.getUserList(depcode, areacode, roles, isand, usertype, startuser, flowuser,
            //         rulecode);



            List<Task> list = processEngine.getTaskService().createTaskQuery().processInstanceId(instance.getId()).list();
            if (!CollectionUtils.isEmpty(list))
                for (Task task : list) {
                    //打印任务中的自定义属性值
                    getCustomizeParam(task.getId());

                    //设置候选人测试
                    processEngine.getTaskService().addCandidateUser(task.getId(), "aaaaa");
                    processEngine.getTaskService().addCandidateUser(task.getId(), "bbbbb");
                    processEngine.getTaskService().saveTask(task);
                    result.put("taskId", task.getId());
                    if (StringUtils.hasLength(task.getAssignee())) {
                        result.put("assignee", task.getAssignee());
                        continue;
                    }
                    List<IdentityLink> identityLinksForTask = processEngine.getTaskService().getIdentityLinksForTask(task.getId());
                    if (!CollectionUtils.isEmpty(identityLinksForTask))
                        for (IdentityLink identityLink : identityLinksForTask) {
                            if (StringUtils.hasLength(identityLink.getUserId())) {
                                result.put(task.getId() + "-user-" + identityLink.getUserId(), identityLink.getUserId());
                            }
                            if (StringUtils.hasLength(identityLink.getGroupId())) {
                                result.put(task.getId() + "-group-" + identityLink.getGroupId(), identityLink.getGroupId());
                            }
                        }
                }



            return ResponseResult.success(result);
        }
        return ResponseResult.error("启动失败");
    }


    @PostMapping(path = "searchByKey")
    @ApiOperation(value = "根据流程key查询流程实例", notes = "查询流程实例")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "processKey", value = "流程key", dataType = "String", paramType = "query", example = ""),
    })
    public ResponseResult searchProcessInstance(@RequestParam("processKey") String processDefinitionKey) {
        List<ProcessInstance> runningList;
        try {
            ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();
            runningList = processInstanceQuery.processDefinitionKey(processDefinitionKey).list();
        } catch (Exception e) {
            return ResponseResult.error("查询失败:" + e.getMessage());
        }

        int size = runningList.size();
        if (size > 0) {
            List<Map<String, String>> resultList = new ArrayList<>();
            for (ProcessInstance pi : runningList) {
                Map<String, String> resultMap = new HashMap<>(4);
                // 流程实例ID
                resultMap.put("processID", pi.getId());
                // 流程定义ID
                resultMap.put("processDefinitionKey", pi.getProcessDefinitionId());
                resultList.add(resultMap);
            }
            return ResponseResult.success(resultList);
        }
        return ResponseResult.success();
    }


    @PostMapping(path = "searchByID")
    @ApiOperation(value = "根据流程key查询流程实例", notes = "查询流程实例")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "processID", value = "流程实例ID", dataType = "String", paramType = "query", example = ""),
    })
    public ResponseResult searchByID(@RequestParam("processID") String processDefinitionID) {
        ProcessInstance pi;
        try {
            pi = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(processDefinitionID)
                    .singleResult();
        } catch (Exception e) {
            log.error(e.getMessage());
            return ResponseResult.error("查询失败:" + e.getMessage());
        }
        if (pi != null) {
            Map<String, String> resultMap = new HashMap<>(4);
            // 流程实例ID
            resultMap.put("processID", pi.getId());
            // 流程定义ID
            resultMap.put("processDefinitionKey", pi.getProcessDefinitionId());
            return ResponseResult.success(resultMap);
        }
        return ResponseResult.success();
    }

    @PostMapping(path = "deleteProcessInstanceByKey")
    @ApiOperation(value = "根据流程实例key删除流程实例", notes = "根据流程实例key删除流程实例")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "processKey", value = "流程实例Key", dataType = "String", paramType = "query", example = ""),
    })
    public ResponseResult deleteProcessInstanceByKey(@RequestParam("processKey") String processDefinitionKey) {
        List<ProcessInstance> runningList;
        try {
            ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();
            runningList = processInstanceQuery.processDefinitionKey(processDefinitionKey).list();
        } catch (Exception e) {
            log.error(e.getMessage());
            return ResponseResult.error("删除失败:" + e.getMessage());
        }

        int size = runningList.size();
        if (size > 0) {
            List<Map<String, String>> resultList = new ArrayList<>();
            for (ProcessInstance pi : runningList) {
                runtimeService.deleteProcessInstance(pi.getId(), "删除");
            }
            return ResponseResult.success(resultList);
        }
        return ResponseResult.success();
    }

    @PostMapping(path = "deleteProcessInstanceByID")
    @ApiOperation(value = "根据流程实例ID删除流程实例", notes = "根据流程实例ID删除流程实例")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "processID", value = "流程实例ID", dataType = "String", paramType = "query", example = ""),
    })
    public ResponseResult deleteProcessInstanceByID(@RequestParam("processID") String processDefinitionID) {
        try {
            runtimeService.deleteProcessInstance(processDefinitionID, "删除" + processDefinitionID);
            return ResponseResult.success();
        } catch (Exception e) {
            log.error(e.getMessage());
            return ResponseResult.error("删除失败:" + e.getMessage());
        }
    }

    @PostMapping(path = "getNextTaskInfo")
    @ApiOperation(value = "根据流程定义id获取下个用户任务信息的信息", notes = "根据流程定义id获取下个用户任务信息的信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "processDefinitionId", value = "流程定义id", dataType = "String", paramType = "query"),
    })
    public ResponseResult<?> getNextTaskInfo(String processDefinitionId,String taskDefinitionId) {
        RepositoryService rs = processEngine.getRepositoryService();
        final BpmnModel bpmnModel = rs.getBpmnModel(processDefinitionId);
        final Process process = bpmnModel.getProcesses().get(0);
        List<FlowElement> nextFlow = new ArrayList<>();
        final Map<String, FlowElement> flowElementMap = process.getFlowElementMap();
        // 不传则任务是取开始节点
        if(StringUtils.isEmpty(taskDefinitionId)) {
            final StartEvent initialFlowElement = (StartEvent) process.getInitialFlowElement();
            final List<SequenceFlow> outgoingFlows = initialFlowElement.getOutgoingFlows();
            for (SequenceFlow outgoingFlow : outgoingFlows) {
                nextFlow.add(flowElementMap.get(outgoingFlow.getTargetRef()));
            }
        }else{
            final FlowElement flowElement = flowElementMap.get(taskDefinitionId);
            if(flowElement instanceof  UserTask){
                getNextUserTask(flowElementMap,(UserTask) flowElement);
            }
        }
        return ResponseResult.error("jjjj");
    }

    private List<UserTask> getNextUserTask(Map<String, FlowElement> flowElementMap, UserTask currentTask){
        List<UserTask> list = new ArrayList<>();
        final List<SequenceFlow> outgoingFlows = currentTask.getOutgoingFlows();
        for (SequenceFlow outgoingFlow : outgoingFlows) {
            final FlowElement targetFlowElement = outgoingFlow.getTargetFlowElement();
            if(targetFlowElement instanceof UserTask){
                list.add((UserTask)targetFlowElement);
            }else{
                if(targetFlowElement instanceof Gateway){

                }
            }
            final FlowElement flowElement = flowElementMap.get(outgoingFlow.getTargetRef());
            if(flowElement instanceof UserTask)
                list.add((UserTask)flowElement);
        }
        return list;
    }


    /**
     * 通过taskId获取流程中自定义属性值
     * @param taskId
     * @return
     */
    public Map<String, List<ExtensionAttribute>> getCustomizeParam(String taskId){
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null){
            return null;
        }
        Map<String, List<ExtensionAttribute>> extensionAttrs = null;
        String processDefId = task.getProcessDefinitionId();
        FlowNode flowNode = findFlowNodeByActivityId(processDefId,task.getTaskDefinitionKey());
        if (flowNode != null && flowNode instanceof UserTask) {
            UserTask userTask = (UserTask) flowNode;
            extensionAttrs = userTask.getAttributes();

        }
        for (String key : extensionAttrs.keySet()){
            System.out.println("====");
            System.out.println("key:"+key);
            System.out.println(extensionAttrs.get(key));
            System.out.println(extensionAttrs.get(key).get(0).getValue());
        }
        return extensionAttrs;
    }

    public FlowNode findFlowNodeByActivityId(String processDefId, String activityId) {
        FlowNode activity = null;
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefId);
        List<Process> processes = bpmnModel.getProcesses();
        for (Process process : processes) {
            FlowElement flowElement = process.getFlowElementMap().get(activityId);
            if (flowElement != null) {
                activity = (FlowNode) flowElement;
                break;
            }
        }
        return activity;
    }




}
